﻿using ICSharpCode.SharpZipLib.Zip;
using UnityEngine;
using UnityEngine.UI;
using System;
using System.Collections;
using System.IO;
using System.Threading;
using System.Text;

namespace CompressTools
{

    public class MainManager : MonoBehaviour
    {

        #region variable

        private Text mLog;
        private Button mStartBtn;
        private Button mStart2Btn;
        private Button mStart3Btn;
        private Button mMD5;

        private Text mFileUrlText;
        private Text mOutputUrlText;
        private Button mSelectFileUrlBtn;
        private Button mSelectOutputUrlBtn;
        private InputField mSetNameInput;

        private string mDefaultFileUrl = "D:/";
        private string mDefaultOutPutUrl = "D:/";
        private string mZipName;

        public delegate void FinishDelegate();
        public static event FinishDelegate FinishEvent;

        private string currentZipUrl;

        #endregion

        #region mono mathod

        void Start()
        {
            UIInit();
        }

        void UIInit()
        {
            Transform canvas = GameObject.Find("Canvas").transform;
            mLog = canvas.Find("Log").GetComponent<Text>();
            mFileUrlText = canvas.Find("FilePanel/FileUrl").GetComponent<Text>();
            mOutputUrlText = canvas.Find("OutputPanel/OutPutUrl").GetComponent<Text>();

            mStartBtn = canvas.Find("Start").GetComponent<Button>();
            mStart2Btn = canvas.Find("Start2").GetComponent<Button>();
            mStart3Btn = canvas.Find("Start3").GetComponent<Button>();
            mMD5 = canvas.Find("MD5").GetComponent<Button>();

            mSelectFileUrlBtn = canvas.Find("FilePanel/SelectUrlBtn").GetComponent<Button>();
            mSelectOutputUrlBtn = canvas.Find("OutputPanel/SelectUrlBtn").GetComponent<Button>();
            mSetNameInput = canvas.Find("OutputPanel/InputField").GetComponent<InputField>();

            mStartBtn.onClick.AddListener(OnStartBtnClick);
            mStart2Btn.onClick.AddListener(OnStart2BtnClick);
            mStart3Btn.onClick.AddListener(OnStart3BtnClick);
            mMD5.onClick.AddListener(OnGetMD5BtnClick);

            mSelectFileUrlBtn.onClick.AddListener(OnSelectFileUrlBtnClick);
            mSelectOutputUrlBtn.onClick.AddListener(OnSelectOutPutUrlBtnClick);
            mSetNameInput.onEndEdit.AddListener(OnSetNameInputEndEdit);

            RefreshUI();
        }

        //压缩文件夹
        void OnStartBtnClick()
        {
            string[] zipPaths = new string[] {
               mDefaultFileUrl
            };

            string outPutUrl = mDefaultOutPutUrl + "/" + mZipName;

            //开始压缩
            StartThread(zipPaths, outPutUrl, null, new MyChineseZipCallback());
        }

        //压缩文件夹下的所有文件(忽略文件夹下的文件夹)
        void OnStart2BtnClick()
        {
            string[] zipPaths = Directory.GetFiles(mDefaultFileUrl);

            string outPutUrl = mDefaultOutPutUrl + "/" + mZipName;

            //开始压缩
            StartThread(zipPaths, outPutUrl, null, new MyChineseZipCallback());
        }

        //压缩文件夹下的所有文件，包括下面的文件夹。和压缩文件夹的区别在于，压缩文件夹会多一个文件夹的层级
        void OnStart3BtnClick()
        {
            string[] foldersPath = Directory.GetDirectories(mDefaultFileUrl);
            string[] filesPath = Directory.GetFiles(mDefaultFileUrl);

            string[] allPaths = new string[foldersPath.Length + filesPath.Length];

            Array.Copy(foldersPath, allPaths, foldersPath.Length);
            Array.Copy(filesPath, 0, allPaths, foldersPath.Length, filesPath.Length);

            string outPutUrl = mDefaultOutPutUrl + "/" + mZipName;

            //开始压缩
            StartThread(allPaths, outPutUrl, null, new MyChineseZipCallback());
        }

        void OnGetMD5BtnClick()
        {
            string[] filesPath = Directory.GetFiles(mDefaultFileUrl);

            filesPath = OptimizeUrl(filesPath);

            for (int i = 0; i < filesPath.Length; i++)
            {
                CreatMD5Code(filesPath[i]);
            }
        }

        void OnSelectFileUrlBtnClick()
        {
            mDefaultFileUrl = WindowsForms.GetDir();
            RefreshUI();

            if (string.IsNullOrEmpty(mSetNameInput.text) && mDefaultFileUrl != null)
            {
                string[] str = mDefaultFileUrl.Split('\\');
                string zipName = str[str.Length - 1] + ".zip";
                mSetNameInput.text = zipName;
                mZipName = zipName;
            }
        }

        void OnSelectOutPutUrlBtnClick()
        {
            mDefaultOutPutUrl = WindowsForms.GetDir();
            RefreshUI();
        }

        void OnDestroy()
        {
            FinishEvent -= ThreadStop;
        }

        #endregion

        #region thread compress

        string[] threadZipPath;
        string threadOutputUrl;
        ZipWrapper.ZipCallback threadZipCallback;
        Thread thread;

        static bool threadSuccess;
        void StartThread(string[] zipPaths, string outputUrl, string passward = null, ZipWrapper.ZipCallback _zipCallback = null)
        {
            if (!outputUrl.Contains(".zip")) return;

            mLog.text = "正在压缩，请稍候...";

            threadSuccess = false;
            EnableUI(false);

            threadZipPath = zipPaths;
            threadOutputUrl = outputUrl;
            threadZipCallback = _zipCallback;

            thread = new Thread(new ThreadStart(ExecuteThread));
            thread.IsBackground = true;
            thread.Start();

            StartCoroutine(MonitorThread());
        }

        void ExecuteThread()
        {

            threadOutputUrl = threadOutputUrl.Replace('\\', '/');

            currentZipUrl = threadOutputUrl;

            ZipWrapper.Zip(threadZipPath, threadOutputUrl, null, threadZipCallback);
        }

        IEnumerator MonitorThread()
        {
            while (true)
            {
                yield return 0;
                if (threadSuccess)
                {
                    break;
                }
            }

            ThreadStop();
        }

        private void ThreadStop()
        {
            if (thread != null)
            {
                thread.Abort();
            }

            mLog.text = "等待压缩...";
            mSetNameInput.text = string.Empty;

            EnableUI(true);
            CreatMD5Code();
        }

        #endregion

        #region tool 
        void CreatMD5Code(string filePath = null)
        {
            if (filePath!=null)
            {
                currentZipUrl = filePath; 
            }

            string configName = "config.txt";
            string configPath = string.Concat(Application.streamingAssetsPath, "/", configName);

            int charCount = currentZipUrl.LastIndexOf('/') + 1;
            string zipName = currentZipUrl.Substring(charCount, currentZipUrl.Length - charCount);

            if (!File.Exists(configPath))
            {
                File.Create(configPath);
            }

            using (FileStream stream = new FileStream(configPath, FileMode.Append))
            {
                string md5Code = MD5Util.CalculateFileMD5(currentZipUrl);

                string keyValue = $"[{zipName}]:[{md5Code}]\r\n";

                byte[] data = Encoding.UTF8.GetBytes(keyValue);
                stream.Write(data, 0, data.Length);

                stream.Close();
                stream.Dispose();
            }
        }

        string GetFileNameByUrl(string url)
        {
            int charCount = url.LastIndexOf('/') + 1;
            string zipName = url.Substring(charCount, url.Length - charCount);

            return zipName;
        }

        public class MyChineseZipCallback : ZipWrapper.ZipCallback
        {

            public override bool OnPreZip(ZipEntry _entry)
            {
                _entry.IsUnicodeText = true;    // 支持中文
                return base.OnPreZip(_entry);
            }

            public override void OnFinished(bool _result)
            {
                threadSuccess = true;
                base.OnFinished(_result);
            }
        }

        void OnSetNameInputEndEdit(string zipNmae)
        {
            mZipName = zipNmae;
        }

        string[] OptimizeUrl(string[] urlArray)
        {
            string[] newUrl = new string[urlArray.Length];

            for (int i = 0; i < urlArray.Length; i++)
            {
                newUrl[i] = urlArray[i].Replace('\\', '/');
            }
            return newUrl;
        }

        void RefreshUI()
        {
            mFileUrlText.text = mDefaultFileUrl;
            mOutputUrlText.text = mDefaultOutPutUrl;
        }

        void EnableUI(bool enable)
        {
            GameObject.Find("Canvas").transform.GetComponent<GraphicRaycaster>().enabled = enable;
        }
        #endregion

    }
}